//
//$Id: islsp_solution.h 726 2012-12-14 19:51:50Z andrew.tsyganov $
#pragma once

#include "src/heo/include/random.h"
#include "src/heo/include/calc_hash.h"
#include "src/heo/include/reflection.h"
#include "src/heo/include/solution.h"
#include "src/heo/include/optimization_direction.h"
#include "src/heo/include/transmit_array.h"
#include "src/heo/include/armadillo.h"

#include "islsp_problem.h"

class Islsp_Solution
{
    //DISALLOW_COPY_AND_ASSIGN(Islsp_Solution);
public:
    typedef double                  TCostType;
    typedef minimization<TCostType> TDirection;

    friend class Islsp_History;

protected:
    Array<double>   t_;
    TCostType       cost_;
    bool            changed_;

    unsigned        hash_;
    bool            hash_changed_;

public:
    explicit Islsp_Solution():
        cost_(),
        changed_(),
        hash_(),
        hash_changed_()
    {}

    template<class E>
    void init(E* env, random_generator& rnd)
    {//:NOTE: may be called several times!
        t_.resize(env->problem_.p_);
    }

    template<class E>
    void generate(E* env, random_generator& rnd)
    {
		for (size_t i = 0; i < t_.size(); ++i)
		{
            t_[i] = env->problem_.Theta0_(i, 0);
		}

        //for (size_t i = 0; i < t_.size(); ++i)
		//{
        //    t_[i] = env->problem_.Delta_(i, 0) + rnd.next_Double() * (env->problem_.Delta_(i, 1) - env->problem_.Delta_(i, 0));
		//}

        changed_ = true;
    }

    Array<double>& get_T()
    {
        return t_;
    }

    void Changed()
    {
        changed_ = true;;
    }

    TCostType get_Cost() const
    {
        ASSERT_(!changed_);
        return cost_;
    }

    unsigned get_Hash()
    {
        ASSERT_(!changed_);
        if (hash_changed_)
        {
            hash_changed_ = false;
            hash_ = Calc_Hash(&t_[0], t_.size() * sizeof(t_[0]));
        }
        return hash_;
    }


	template<class E>
	TCostType J_MLF_KF(E* env, random_generator& rnd);

    template<class E>
    void evaluate_Correction_MLF_KF(E* env, Array<double>& c);

    template<class E>
    TCostType J_MLF_SR(E* env, random_generator& rnd);

	template<class E>
	void evaluate_Correction_MLF_SR(E* env, Array<double>& c);

	template<class E>
    TCostType J_LS_KF(E* env, random_generator& rnd);

	template<class E>
    TCostType J_APF_KF(E* env, random_generator& rnd);


    template<class E>
    void evaluate(E* env, random_generator& rnd)
    {
        if (!changed_)
            return;
        changed_ = false;
        hash_changed_ = true;

		///////////////////////////////////////////////


        ///////////////////////////////////////////////
        
		if (env->cfg_.method_ == "mlf_kf")  
		{
			cost_ = J_MLF_KF(env, rnd);
		}
		else
		{
			if (env->cfg_.method_ == "mlf_sr")
			{
				cost_ = J_MLF_SR(env, rnd);
			}
		}

        //cost_ = J_APF(env, rnd);
        //cost_ = J_LS(env, rnd);
    }

    void subs_Parameters_V(std::vector<arma::mat> const& v_m_src, std::vector<param_pos> const& v_pos, std::vector<arma::mat>& v_m_dest)
    {
        for (size_t i = 0; i < v_m_src.size(); ++i)
            subs_Parameters(v_m_src[i], v_pos[i], v_m_dest[i]);
    };

    void subs_Parameters(arma::mat const& m_src, param_pos const& pos, arma::mat& m_dest)
    {
        m_dest = m_src;

        for (size_t m = 0; m < pos.size(); ++m)
            for (size_t n = 0; n < pos[m].size(); ++n)
            {
                pair p = pos[m][n];
                m_dest(p.i_, p.j_) = t_[m];
            }
    };

    template<class V>
    void accept(V& v)
    {
        v(t_);
        v(cost_);
        v(changed_);

        v(hash_);
        v(hash_changed_);
    }

    void assign(Islsp_Solution const& sol)
    {
        t_              = sol.t_;
        cost_           = sol.cost_;
        changed_        = sol.changed_;

        hash_           = sol.hash_;
        hash_changed_   = sol.hash_changed_;
    }

    template<class X>
    void copy_To(X& x) const
    {
        x.assign(*this);
    }

	template<class E>
    void print(std::ostream& os, E* env)
    {
        double residual = 0;
        for (size_t i = 0; i < t_.size(); ++i)
        {
            double tmp = t_[i] - env->problem_.Theta_(i, 0);
            residual += tmp * tmp;
        }
        residual = sqrt(residual);

        os << "cost = " << get_Cost() << lf
            << "Theta = (";
        for (size_t i = 0; i < t_.size() - 1; ++i)
        {
            os << t_[i] << "; ";
        }
        os << t_[t_.size() - 1] << ")"
            << lf << "residual = " << residual;
        
    }

    template<class E>
    static bool read(E* env, std::string const& file_name, Solution_Pool<Islsp_Solution>& pool)
    {
        //:see onemax.h for example
        return false;
    }

    template<class E>
    void write(E* env, std::string const& file_name, size_t id, size_t count)
    {
        //:see onemax.h for example
    }
};


//EOF!
